#include "stdafx.h"
#include "LogViewer.h"

using std::map;


static HICON g_icon = 0;

[
	coclass,
	threading(apartment),
	uuid("66EA2A31-B52E-4375-BF90-BFB57B5D082E")
]
class ATL_NO_VTABLE CRichObj : public IRichObj, public IViewObject
{
public:
	CComPtr<IOleClientSite> m_site;
	SIZEL m_sz; // client size
	DWORD m_dwconn; //for connection.
	map<DWORD,CComPtr<IAdviseSink> > m_pSinks;
	PBYTE m_data;
	DWORD m_dataLen;

	CRichObj()
	{
		m_dwconn = 1;
		m_sz.cx = 16;
		m_sz.cy = 16;
		m_data = 0;
		m_dataLen = 0;
	}
	~CRichObj()
	{
		delete [] m_data;
	}
	void Pixel2HIMETRIC(LONG &x,LONG &y,HDC hDC = 0)
	{
		HDC hdc = 0;
		if(hDC == 0) hdc = hDC = GetDC(0);
		x = x*2540/GetDeviceCaps(hDC,LOGPIXELSX);
		y = y*2540/GetDeviceCaps(hDC,LOGPIXELSY);
		if(hdc) ReleaseDC(0,hdc);
	}

	HRESULT STDMETHODCALLTYPE SetClientSite(IOleClientSite *pClientSite)
	{
		m_site = pClientSite;
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetClientSite(IOleClientSite** ppClientSite)
	{
		*ppClientSite = m_site;
		if(m_site) m_site.p->AddRef();
		return m_site ? 0 : E_UNEXPECTED;
	}

	HRESULT STDMETHODCALLTYPE SetHostNames(LPCOLESTR szContainerApp,LPCOLESTR szContainerObj)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE Close(DWORD dwSaveOption)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE SetMoniker(DWORD dwWhichMoniker,IMoniker *pmk)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign,DWORD dwWhichMoniker,IMoniker ** ppmk)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE InitFromData(IDataObject *pDataObject,BOOL fCreation,DWORD dwReserved)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetClipboardData(DWORD dwReserved,IDataObject ** ppDataObject)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE DoVerb(LONG iVerb,LPMSG lpmsg,IOleClientSite *pActiveSite,LONG lindex,HWND hwndParent,LPCRECT lprcPosRect)
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE EnumVerbs(IEnumOLEVERB ** ppEnumOleVerb)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE Update()
	{
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE IsUpToDate()
	{
		return S_FALSE;
	}

	HRESULT STDMETHODCALLTYPE GetUserClassID(CLSID *pClsid)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetUserType(DWORD dwFormOfType,LPOLESTR *pszUserType)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE SetExtent(DWORD dwDrawAspect,SIZEL *psizel)
	{
		//m_sz = *psizel;
		return E_FAIL;
	}

	HRESULT STDMETHODCALLTYPE GetExtent(DWORD dwDrawAspect,SIZEL *psizel)
	{
		*psizel = m_sz;
		Pixel2HIMETRIC(psizel->cx,psizel->cy);
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE Advise(IAdviseSink *pAdvSink,DWORD *pdwConnection)
	{
		if(!pAdvSink) return E_INVALIDARG;
		*pdwConnection = m_dwconn;
		m_pSinks[m_dwconn] = pAdvSink;
		++ m_dwconn;
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwConnection)
	{
		m_pSinks.erase(dwConnection);
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE EnumAdvise(IEnumSTATDATA ** ppenumAdvise)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetMiscStatus(DWORD dwAspect,DWORD *pdwStatus)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE SetColorScheme(LOGPALETTE *pLogpal)
	{
		return S_OK;
	}

	////// iview related
	HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect,LONG lindex,
		void *pvAspect,DVTARGETDEVICE *ptd,HDC hdcTargetDev,
		HDC hdcDraw,LPCRECTL lprcBounds,LPCRECTL lprcWBounds,
		BOOL ( STDMETHODCALLTYPE *pfnContinue )(DWORD dwContinue),
		DWORD dwContinue)
	{
		if(!lprcBounds) return E_UNEXPECTED;
		RECT rc = {lprcBounds->left,lprcBounds->top,lprcBounds->right,lprcBounds->bottom};
		if (g_icon == NULL)
		{
			g_icon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_OBJ), IMAGE_ICON, 16, 16, LR_SHARED);
		}
		DrawIconEx(hdcDraw, rc.left, rc.top, g_icon, 16, 16, 0, 0, DI_NORMAL);
		return S_OK;
	}

	HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect,LONG lindex,void *pvAspect,DVTARGETDEVICE *ptd,
		HDC hicTargetDev,LOGPALETTE ** ppColorSet)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect,LONG lindex,void *pvAspect,DWORD *pdwFreeze)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects,DWORD advf,IAdviseSink *pAdvSink)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects,DWORD *pAdvf,IAdviseSink ** ppAdvSink)
	{
		return E_NOTIMPL;
	}

	HRESULT STDMETHODCALLTYPE GetExtent(DWORD dwDrawAspect,LONG lindex,DVTARGETDEVICE *ptd,LPSIZEL psizel)
	{
		*psizel = m_sz;
		Pixel2HIMETRIC(psizel->cx,psizel->cy);
		return S_OK;
	}

	//our obj.
	HRESULT STDMETHODCALLTYPE TrackFrameChange()
	{
		std::map<DWORD, CComPtr<IAdviseSink> >::iterator p = m_pSinks.begin();
		for(; p!=m_pSinks.end(); ++p)
		{
			if(p->second)
			{
				p->second->OnViewChange(DVASPECT_CONTENT,-1);
			}
		}
		return S_OK;
	}
	HRESULT LoadFromMemory(BYTE * pMem,DWORD len)
	{
		delete [] m_data;
		m_dataLen = len;
		if (len)
		{
			m_data = (PBYTE)memcpy(malloc(len), pMem, len);
		}
		else
		{
			m_data = 0;
		}
		return S_OK;
	}
	HRESULT GetData(BYTE * pMem, DWORD inSz, DWORD * outsz)
	{
		if (!outsz) return E_FAIL;
		if (!pMem)
		{
			*outsz = m_dataLen;
			return S_OK;
		}
		*outsz = min(m_dataLen, inSz);
		memcpy(pMem, m_data, *outsz);
		return S_OK;
	}
};

BOOL GetRichObj(IRichObj ** pRichPic)
{
	if(!pRichPic) return FALSE;
	*pRichPic = new CComObjectNoLock<CRichObj>;
	(*pRichPic)->AddRef();
	return TRUE;
}
